/*
 * MIT License
 * Copyright (c) 2019 - 2025 _VIFEXTech
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "timer.h"

/*定时器编号枚举*/
typedef enum {
    TIMER1,
    TIMER2,
    TIMER3,
    TIMER6,
    TIMER14,
    TIMER15,
    TIMER16,
    TIMER17,
    TIMER_MAX
} TIMERx_Type;

/*定时中断回调函数指针数组*/
static Timer_CallbackFunction_t TIMx_Function[TIMER_MAX] = { 0 };

/**
 * @brief  启动或关闭指定定时器的时钟
 * @param  TIMx:定时器地址
 * @param  NewState: ENABLE启动，DISABLE关闭
 * @retval 无
 */
void Timer_ClockCmd(TIM_TypeDef* TIMx, FunctionalState NewState)
{
    if (TIMx == TIM1) {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, NewState);
    } else if (TIMx == TIM2) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, NewState);
    } else if (TIMx == TIM3) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, NewState);
    } else if (TIMx == TIM6) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, NewState);
    } else if (TIMx == TIM14) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, NewState);
    } else if (TIMx == TIM15) {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, NewState);
    } else if (TIMx == TIM16) {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, NewState);
    } else {
        if (TIMx == TIM17) {
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM17, NewState);
        }
    }
}

/*取绝对值*/
#define CLOCK_ABS(x) (((x) > 0) ? (x) : -(x))

/*快速求平方根*/
static float Qsqrt(float number)
{
    long i;
    float x2, y;
    const float threehalfs = 1.5f;
    x2 = number * 0.5f;
    y = number;
    i = *(long*)&y;
    i = 0x5f3759df - (i >> 1);
    y = *(float*)&i;
    y = y * (threehalfs - (x2 * y * y));
    y = y * (threehalfs - (x2 * y * y));
    return 1.0f / y;
}

/**
 * @brief  将定时中断频率转换为重装值和时钟分频值
 * @param  freq: 中断频率(Hz)
 * @param  clock: 定时器时钟
 * @param  *period: 重装值地址
 * @param  *prescaler: 时钟分频值地址
 * @retval 误差值(Hz)
 */
static int32_t Timer_FreqToArrPsc(
    uint32_t freq, uint32_t clock,
    uint16_t* period, uint16_t* prescaler)
{
    uint32_t prodect;
    uint16_t psc, arr, arr_max;
    uint16_t max_error = 0xFFFF;

    if (freq == 0 || freq > clock)
        goto failed;

    /*获取arr和psc目标乘积*/
    prodect = clock / freq;

    /*从prodect的平方根开始计算*/
    psc = Qsqrt(prodect);

    /*arr必定小于等于prodect，尽量减少arr遍历次数*/
    arr_max = (prodect < 0xFFFF) ? prodect : 0xFFFF;

    /*遍历，使arr*psc足够接近prodect*/
    for (; psc > 1; psc--) {
        for (arr = psc; arr < arr_max; arr++) {
            /*求误差*/
            int32_t newerr = arr * psc - prodect;
            newerr = CLOCK_ABS(newerr);
            if (newerr < max_error) {
                /*保存最小误差*/
                max_error = newerr;
                /*保存arr和psc*/
                *period = arr;
                *prescaler = psc;
                /*最佳*/
                if (max_error == 0)
                    goto success;
            }
        }
    }

    /*计算成功*/
success:
    return (freq - clock / ((*period) * (*prescaler)));

    /*失败*/
failed:
    return (freq - clock);
}

/**
 * @brief  将定时中断时间转换为重装值和时钟分频值
 * @param  time: 中断时间(微秒)
 * @param  clock: 定时器时钟
 * @param  *period: 重装值地址
 * @param  *prescaler: 时钟分频值地址
 * @retval 无
 */
static void Timer_TimeToArrPsc(
    uint32_t time, uint32_t clock,
    uint16_t* period, uint16_t* prescaler)
{
    uint32_t cyclesPerMicros = clock / 1000000U;
    uint32_t prodect = time * cyclesPerMicros;
    uint16_t arr, psc;

    if (prodect < cyclesPerMicros * 30) {
        arr = 10;
        psc = prodect / arr;
    } else if (prodect < 65535 * 1000) {
        arr = prodect / 1000;
        psc = prodect / arr;
    } else {
        arr = prodect / 20000;
        psc = prodect / arr;
    }
    *period = arr;
    *prescaler = psc;
}

/**
 * @brief  定时器使能
 * @param  TIMx: 定时器地址
 * @param  Enable: 使能
 * @retval 无
 */
void Timer_SetEnable(TIM_TypeDef* TIMx, bool Enable)
{
    TIM_Cmd(TIMx, Enable ? ENABLE : DISABLE);
}

/**
 * @brief  定时中断配置
 * @param  TIMx:定时器地址
 * @param  time: 中断时间(微秒)
 * @param  function: 定时中断回调函数
 * @retval 无
 */
void Timer_SetInterrupt(TIM_TypeDef* TIMx, uint32_t time, Timer_CallbackFunction_t function)
{
    uint16_t period, prescaler;
    uint32_t clock = Timer_GetClockMax(TIMx);

    if (!IS_TIM_ALL_PERIPH(TIMx) || time == 0)
        return;

    /*将定时中断时间转换为重装值和时钟分频值*/
    Timer_TimeToArrPsc(
        time,
        clock,
        &period,
        &prescaler);

    /*定时中断配置*/
    Timer_SetInterruptBase(
        TIMx,
        period,
        prescaler,
        function,
        Timer_ChannelPriority_Default,
        0);
}

/**
 * @brief  更新定时中断频率
 * @param  TIMx:定时器地址
 * @param  freq:中断频率
 * @retval 无
 */
void Timer_SetInterruptFreqUpdate(TIM_TypeDef* TIMx, uint32_t freq)
{
    uint16_t period, prescaler;
    uint32_t clock = Timer_GetClockMax(TIMx);

    if (!IS_TIM_ALL_PERIPH(TIMx) || freq == 0)
        return;

    Timer_FreqToArrPsc(
        freq,
        clock,
        &period,
        &prescaler);
    TIM_SetAutoreload(TIMx, period - 1);
    TIM_PrescalerConfig(TIMx, prescaler - 1, TIM_PSCReloadMode_Immediate);
}

/**
 * @brief  获取定时器中断频率
 * @param  TIMx:定时器地址
 * @retval 中断频率
 */
uint32_t Timer_GetClockOut(TIM_TypeDef* TIMx)
{
    uint32_t clock = Timer_GetClockMax(TIMx);
    if (!IS_TIM_ALL_PERIPH(TIMx))
        return 0;

    return (clock / ((TIMx->ARR + 1) * (TIMx->PSC + 1)));
}

/**
 * @brief  更新定时中断时间
 * @param  TIMx:定时器地址
 * @param  time: 中断时间(微秒)
 * @retval 无
 */
void Timer_SetInterruptTimeUpdate(TIM_TypeDef* TIMx, uint32_t time)
{
    uint16_t period, prescaler;
    uint32_t clock = Timer_GetClockMax(TIMx);

    if (!IS_TIM_ALL_PERIPH(TIMx))
        return;

    Timer_TimeToArrPsc(
        time,
        clock,
        &period,
        &prescaler);
    TIM_SetAutoreload(TIMx, period - 1);
    TIM_PrescalerConfig(TIMx, prescaler - 1, TIM_PSCReloadMode_Immediate);
}

/**
 * @brief  定时中断基本配置
 * @param  TIMx:定时器地址
 * @param  period:重装值
 * @param  prescaler:时钟分频值
 * @param  function: 定时中断回调函数
 * @param  ChannelPriority: 通道优先级
 * @retval 无
 */
void Timer_SetInterruptBase(
    TIM_TypeDef* TIMx,
    uint16_t period, uint16_t prescaler,
    Timer_CallbackFunction_t function,
    uint8_t ChannelPriority,
    uint8_t SubPriority)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    uint8_t TIMx_IRQn;
    TIMERx_Type TIMERx;
    (void)SubPriority;

    if (!IS_TIM_ALL_PERIPH(TIMx))
        return;

#define TIMx_IRQ_DEF(n, x_IRQn) \
    do {                        \
        if (TIMx == TIM##n) {   \
            TIMERx = TIMER##n;  \
            TIMx_IRQn = x_IRQn; \
        }                       \
    } while (0)

    TIMx_IRQ_DEF(1, TIM1_BRK_UP_TRG_COM_IRQn);
    TIMx_IRQ_DEF(2, TIM2_IRQn);
    TIMx_IRQ_DEF(3, TIM3_IRQn);
    TIMx_IRQ_DEF(6, TIM6_DAC_IRQn);
    TIMx_IRQ_DEF(14, TIM14_IRQn);
    TIMx_IRQ_DEF(15, TIM15_IRQn);
    TIMx_IRQ_DEF(16, TIM16_IRQn);
    TIMx_IRQ_DEF(17, TIM17_IRQn);

    if (TIMx_IRQn == 0)
        return;

    /*register callback function*/
    TIMx_Function[TIMERx] = function;

    /*Enable PeriphClock*/
    TIM_DeInit(TIMx);
    Timer_ClockCmd(TIMx, ENABLE);

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseStructure.TIM_Period = period - 1; // 设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_Prescaler = prescaler - 1; // 设置用来作为TIMx时钟频率除数的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 设置分频
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // TIM向上计数模式
    TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);

    /**********************************设置中断优先级************************************/
    NVIC_InitStructure.NVIC_IRQChannel = TIMx_IRQn; // TIM中断
    NVIC_InitStructure.NVIC_IRQChannelPriority = ChannelPriority;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);

    TIM_ClearFlag(TIMx, TIM_FLAG_Update);
    TIM_ClearITPendingBit(TIMx, TIM_IT_Update);
    TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE); // 使能TIM中断
}

#define TIMx_IRQHANDLER(n)                                     \
    do {                                                       \
        if (TIM_GetITStatus(TIM##n, TIM_IT_Update) != RESET) { \
            if (TIMx_Function[TIMER##n])                       \
                TIMx_Function[TIMER##n]();                     \
            TIM_ClearITPendingBit(TIM##n, TIM_IT_Update);      \
        }                                                      \
    } while (0)

/**
 * @brief  定时中断入口，定时器1
 * @param  无
 * @retval 无
 */
void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
{
    TIMx_IRQHANDLER(1);
}

/**
 * @brief  定时中断入口，定时器2
 * @param  无
 * @retval 无
 */
void TIM2_IRQHandler(void)
{
    TIMx_IRQHANDLER(2);
}

/**
 * @brief  定时中断入口，定时器3
 * @param  无
 * @retval 无
 */
void TIM3_IRQHandler(void)
{
    TIMx_IRQHANDLER(3);
}

/**
 * @brief  定时中断入口，定时器6
 * @param  无
 * @retval 无
 */
void TIM6_DAC_IRQHandler(void)
{
    TIMx_IRQHANDLER(6);
}

/**
 * @brief  定时中断入口，定时器14
 * @param  无
 * @retval 无
 */
void TIM14_IRQHandler(void)
{
    TIMx_IRQHANDLER(14);
}

/**
 * @brief  定时中断入口，定时器15
 * @param  无
 * @retval 无
 */
void TIM15_IRQHandler(void)
{
    TIMx_IRQHANDLER(15);
}

/**
 * @brief  定时中断入口，定时器16
 * @param  无
 * @retval 无
 */
void TIM16_IRQHandler(void)
{
    TIMx_IRQHANDLER(16);
}

/**
 * @brief  定时中断入口，定时器17
 * @param  无
 * @retval 无
 */
void TIM17_IRQHandler(void)
{
    TIMx_IRQHANDLER(17);
}
